package main

import (
	"fmt"         // 导入 fmt 包，用于格式化输入输出
	"math/rand"    // 导入 math/rand 包，用于生成随机数
	"sync/atomic" // 导入 sync/atomic 包，用于进行原子操作
	"time"        // 导入 time 包，用于处理时间相关操作
)

// 定义一个结构体 readOp，表示一个读取操作
type readOp struct {
	key  int       // 需要读取的 key
	resp chan int  // 用于发送读取结果的通道
}

// 定义一个结构体 writeOp，表示一个写入操作
type writeOp struct {
	key  int       // 需要写入的 key
	val  int       // 需要写入的值
	resp chan bool // 用于通知写入完成的通道
}

func main() {
	// 声明两个变量，用于原子地记录读取和写入的操作次数
	var readOps uint64
	var writeOps uint64

	// 创建两个通道，分别用于发送读取和写入的操作
	reads := make(chan readOp)
	writes := make(chan writeOp)

	// 启动一个 Goroutine 来管理状态
	go func() {
		// 这个 Goroutine 维护着一个 map 作为状态
		var state = make(map[int]int)
		// 无限循环，等待读取或写入操作
		for {
			// 使用 select 语句同时监听 reads 和 writes 两个通道
			select {
			// 如果从 reads 通道接收到一个 readOp
			case read := <-reads:
				// 根据 readOp 中的 key 从 state map 中读取值，并通过 resp 通道发送回发起者
				read.resp <- state[read.key]
			// 如果从 writes 通道接收到一个 writeOp
			case write := <-writes:
				// 根据 writeOp 中的 key 和 val 更新 state map
				state[write.key] = write.val
				// 通过 resp 通道通知发起者写入已完成
				write.resp <- true
			}
		}
	}()

	// 启动 100 个 Goroutine 来执行读取操作
	for r := 0; r < 100; r++ {
		go func() {
			// 每个读取 Goroutine 进入无限循环
			for {
				// 创建一个 readOp 结构体
				read := readOp{
					key:  rand.Intn(5),      // 随机生成一个 0 到 4 的 key
					resp: make(chan int), // 为这个读取操作创建一个新的响应通道
				}
				// 将读取操作发送到 reads 通道
				reads <- read
				// 阻塞等待读取结果从 read.resp 通道返回
				<-read.resp
				// 原子地增加读取操作计数器
				atomic.AddUint64(&readOps, 1)
				// 暂停 1 毫秒
				time.Sleep(time.Millisecond)
			}
		}()
	}

	// 启动 10 个 Goroutine 来执行写入操作
	for w := 0; w < 10; w++ {
		go func() {
			// 每个写入 Goroutine 进入无限循环
			for {
				// 创建一个 writeOp 结构体
				write := writeOp{
					key:  rand.Intn(5),       // 随机生成一个 0 到 4 的 key
					val:  rand.Intn(100),     // 随机生成一个 0 到 99 的 value
					resp: make(chan bool), // 为这个写入操作创建一个新的响应通道
				}
				// 将写入操作发送到 writes 通道
				writes <- write
				// 原子地增加写入操作计数器
				atomic.AddUint64(&writeOps, 1)
				// 暂停 1 毫秒
				time.Sleep(time.Millisecond)
			}
		}()
	}

	// 主 Goroutine 睡眠 1 秒钟，给其他的 Goroutine 执行的时间
	time.Sleep(time.Second)

	// 原子地加载最终的读取操作计数
	readOpsFinal := atomic.LoadUint64(&readOps)
	fmt.Println("readOps:", readOpsFinal)
	// 原子地加载最终的写入操作计数
	writeOpsFinal := atomic.LoadUint64(&writeOps)
	fmt.Println("writeOps:", writeOpsFinal)
}